#include "TcpServer.h"
#include "event2/buffer.h"
#include <thread>
#include <chrono>
#if __linux__
#include <sys/socket.h>
#endif


void socket_read_cb(bufferevent *bev, void *arg)
{
#if 0 // buffer的长度、复制和移除操作
    // char msg[4096];    

    // size_t bufLen = evbuffer_get_length(bev->input);
    // std::cout << "input buf len: " << bufLen << std::endl;

    // char cp[1024];
    // evbuffer_copyout(bev->input, &cp, 5);
    // std::cout << "cp: " << cp << std::endl;
    // // evbuffer_remove(bev->input, cp, 1);
    // evbuffer_drain(bev->input, 2);

    // size_t len = bufferevent_read(bev, msg, sizeof(msg)-1 );    

    // msg[len] = '\0';    
    // printf("server read the data %s\n", msg);    

    // bufferevent_write(bev, msg, len);    
#elif 0 // 行读取
    size_t len;
    char *request = evbuffer_readln(bev->input, &len, EVBUFFER_EOL_LF);
    if (request) {
        std::string tmp(request, len);
        std::cout << "Recv: " << tmp << std::endl;
        bufferevent_write(bev, request, len);
    }
#elif 0 // buffer的搜索查找
    const char head[] = "Hello";
    size_t len = strlen(head);
    evbuffer_ptr p;
    evbuffer_ptr_set(bev->input, &p, 0, EVBUFFER_PTR_SET);
    p = evbuffer_search(bev->input, head, len, &p);
    if (p.pos < 0) {
        std::cout << "evbuffer have not Head." << std::endl;
        return;
    }
    // evbuffer_ptr_set(bev->input, &p, len, EVBUFFER_PTR_ADD);

    std::cout << "Head pos: " << p.pos << std::endl;
    if (p.pos == 0) {
        evbuffer_drain(bev->input, len);
    }
    size_t bufLen = evbuffer_get_length(bev->input);
    char msg[4096];    
    size_t msgLen = bufferevent_read(bev, msg, sizeof(msg)-1 );    

    msg[msgLen] = '\0';    
    printf("server read the data %s\n", msg);    

    bufferevent_write(bev, msg, msgLen);    
#elif 1 // 检测而不复制
    // std::this_thread::sleep_for(std::chrono::seconds(15));
    evbuffer_ptr p;
    evbuffer_ptr_set(bev->input, &p, 0, EVBUFFER_PTR_SET);
    evbuffer_iovec v[1];
    int rst = evbuffer_peek(bev->input, -1, &p, v, 1);
    if (rst < 1) {
        std::cout << "evbuffer_peek < 1" << std::endl;
        return;
    }
    std::string tmp((char*)(v[0].iov_base), v[0].iov_len);
    std::cout << "peek: " << tmp << std::endl;

    char msg[4096];    
    size_t msgLen = bufferevent_read(bev, msg, sizeof(msg)-1 );    
    msg[msgLen] = '\0';    
    printf("server read the data %s\n", msg);    
    bufferevent_write(bev, tmp.c_str(), tmp.size());    
#endif
}

void socket_event_cb(bufferevent *bev, short events, void *arg)
{
    if (events & BEV_EVENT_EOF)    
        printf("connection closed\n");    
    else if (events & BEV_EVENT_ERROR)    
        printf("some other error\n");    

    //这将自动close套接字和free读写缓冲区    
    bufferevent_free(bev);    
}

void listener_cb(evconnlistener *listener, evutil_socket_t fd,
                 sockaddr *sock, int socklen, void *arg)
{
    std::cout << "accept a client " << fd << std::endl;
    CTcpServer *pTcp = (CTcpServer *)arg;

    CTcpServer::Tcb tcb;
    char ip[32] = {0};
    if (evutil_inet_ntop(AF_INET, (void*)((in_addr*)sock->sa_data), ip, 32) == nullptr) {
        std::cout << "evutil_inet_ntop == nullptr" << std::endl;
        return;
    }
    int port = ((sockaddr_in *)sock)->sin_port;
    // std::cout << "ip: " << ip << ", port: " << port << std::endl;

    tcb.pBev = bufferevent_socket_new(pTcp->_pBase, fd, BEV_OPT_CLOSE_ON_FREE);

    bufferevent_setcb(tcb.pBev, socket_read_cb, nullptr, socket_event_cb, nullptr);
    bufferevent_enable(tcb.pBev, EV_READ | EV_PERSIST);

    pTcp->_clients.push_back(tcb);

    // std::this_thread::sleep_for(std::chrono::seconds(30));
    std::cout << "ip: " << ip << ", port: " << port << std::endl;
}

CTcpServer::CTcpServer(const uint16_t &listenPort, const std::string &ip/*="0.0.0.0"*/)
    : _listenPort(listenPort), _listenIp(ip)
{
    _pBase = event_base_new();
}

CTcpServer::~CTcpServer()
{
    evconnlistener_free(_pListener);
    event_base_free(_pBase); 
}

bool CTcpServer::SetReadMsgCB(ReadMsgCB msgCB)
{
    _readMsgCB = msgCB;
    return true;
}

bool CTcpServer::SetStatusCB(StatusCB statusCB)
{
    _statusCB = statusCB;
    return true;
}

bool CTcpServer::SendMsg(const std::string &msg)
{
    return true;
}

bool CTcpServer::Run()
{
    if (_pListener !=nullptr) {
        std::cout << "_pListener !=nullptr" << std::endl;
        return false;
    }
    std::cout << "---> 1" << std::endl;
    std::cout << "-- _listenPort: " << _listenPort
              << ", _listenIp: " << _listenIp << std::endl;

    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(_listenPort);
    // inet_aton(_listenIp.c_str(), &sin.sin_addr);

    int sinAddrRst = evutil_inet_pton(AF_INET, _listenIp.c_str(), &sin.sin_addr);
    if (sinAddrRst == -1) {
        std::cout << "evutil_inet_pton failed." << std::endl;
        return false;
    }

    _pListener = evconnlistener_new_bind(_pBase, listener_cb, this,
        LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, 10, (sockaddr *)&sin, sizeof(sockaddr_in)
    );
    std::cout << "---> dispatch...." << std::endl;
    event_base_dispatch(_pBase);
    std::cout << "---> exit" << std::endl;
    return true;
}